﻿using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Net8.Project.Common.HttpContextUser;
using Net8.Project.Model.Options;
using System.Reflection;

namespace Net8.Project.Common.Core
{
    /// <summary>
    /// 应用全局静态辅助类。
    /// 提供非依赖注入方式获取 Service、Options、配置、环境等功能。
    /// </summary>
    public class App
    {
        static App()
        {
            // 初始化所有有效类型
            EffectiveTypes = Assemblies.SelectMany(GetTypes);
        }

        private static bool _isRun;

        /// <summary>
        /// 应用是否已构建（Build）
        /// </summary>
        public static bool IsBuild { get; set; }

        /// <summary>
        /// 应用是否正在运行（Run），设置时会同步设置 IsBuild
        /// </summary>
        public static bool IsRun
        {
            get => _isRun;
            set => _isRun = IsBuild = value;
        }

        /// <summary>
        /// 应用有效程序集集合
        /// </summary>
        public static readonly IEnumerable<Assembly> Assemblies = RuntimeExtension.GetAllAssemblies();

        /// <summary>
        /// 应用有效类型集合
        /// </summary>
        public static readonly IEnumerable<Type> EffectiveTypes;

        /// <summary>
        /// 全局服务提供器（Root），建议优先通过 App.GetService 获取服务
        /// </summary>
        public static IServiceProvider RootServices => IsRun || IsBuild ? InternalApp.RootServices : null;

        /// <summary>
        /// 获取 Web 主机环境（如开发、生产等）
        /// </summary>
        public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment;

        /// <summary>
        /// 获取泛型主机环境（如开发、生产等）
        /// </summary>
        public static IHostEnvironment HostEnvironment => InternalApp.HostEnvironment;

        /// <summary>
        /// 全局配置对象
        /// </summary>
        public static IConfiguration Configuration => InternalApp.Configuration;

        /// <summary>
        /// 获取当前请求的 HttpContext
        /// </summary>
        public static HttpContext HttpContext => RootServices?.GetService<IHttpContextAccessor>()?.HttpContext;

        /// <summary>
        /// 获取当前用户上下文对象
        /// </summary>
        public static IUser User => GetService<IUser>();

        #region Service

        /// <summary>
        /// 获取服务提供器（根据服务类型、生命周期等自动选择）
        /// </summary>
        /// <param name="serviceType">服务类型</param>
        /// <param name="mustBuild">是否必须已构建</param>
        /// <param name="throwException">是否抛出异常</param>
        /// <returns>服务提供器</returns>
        /// <exception cref="ApplicationException"></exception>
        public static IServiceProvider GetServiceProvider(Type serviceType, bool mustBuild = false, bool throwException = true)
        {
            // 优先返回 RootServices（单例服务或已构建）
            if (HostEnvironment == null || RootServices != null &&
                InternalApp.InternalServices
                    .Any(u =>
                        u.ServiceType ==
                        (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType) &&
                        u.Lifetime == ServiceLifetime.Singleton))
                return RootServices;

            // 请求作用域服务
            if (HttpContext?.RequestServices != null)
                return HttpContext.RequestServices;

            // 创建新的作用域
            if (RootServices != null)
            {
                IServiceScope scope = RootServices.CreateScope();
                return scope.ServiceProvider;
            }

            // 必须已构建但未构建时抛异常
            if (mustBuild)
            {
                if (throwException)
                    throw new ApplicationException("当前不可用，必须要等到 WebApplication Build后");
                return default;
            }

            // 构建新的 ServiceProvider（仅限特殊场景）
            ServiceProvider serviceProvider = InternalApp.InternalServices.BuildServiceProvider();
            return serviceProvider;
        }

        /// <summary>
        /// 获取指定类型的服务（全局作用域）
        /// </summary>
        /// <typeparam name="TService">服务类型</typeparam>
        /// <param name="mustBuild">是否必须已构建</param>
        /// <returns>服务实例</returns>
        public static TService GetService<TService>(bool mustBuild = true) where TService : class =>
            GetService(typeof(TService), null, mustBuild) as TService;

        /// <summary>
        /// 获取指定类型的服务（指定服务提供器）
        /// </summary>
        /// <typeparam name="TService">服务类型</typeparam>
        /// <param name="serviceProvider">服务提供器</param>
        /// <param name="mustBuild">是否必须已构建</param>
        /// <returns>服务实例</returns>
        public static TService GetService<TService>(IServiceProvider serviceProvider, bool mustBuild = true)
            where TService : class =>
            (serviceProvider ?? GetServiceProvider(typeof(TService), mustBuild, false))?.GetService<TService>();

        /// <summary>
        /// 获取指定类型的服务（可指定服务提供器）
        /// </summary>
        /// <param name="type">服务类型</param>
        /// <param name="serviceProvider">服务提供器</param>
        /// <param name="mustBuild">是否必须已构建</param>
        /// <returns>服务实例</returns>
        public static object GetService(Type type, IServiceProvider serviceProvider = null, bool mustBuild = true) =>
            (serviceProvider ?? GetServiceProvider(type, mustBuild, false))?.GetService(type);

        #endregion

        #region private

        /// <summary>加载程序集中的所有类型</summary>
        /// <param name="ass"></param>
        /// <returns></returns>
        private static IEnumerable<Type> GetTypes(Assembly ass)
        {
            Type[] source = Array.Empty<Type>();
            try
            {
                source = ass.GetTypes();
            }
            catch
            {
                Console.WriteLine($@"Error load `{ass.FullName}` assembly.");
            }

            return source.Where(u => u.IsPublic);
        }

        #endregion

        #region Options

        /// <summary>获取配置</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <returns>TOptions</returns>
        public static TOptions GetConfig<TOptions>()
            where TOptions : class, IConfigurableOptions
        {
            TOptions instance = Configuration
                .GetSection(ConfigurableOptions.GetConfigurationPath(typeof(TOptions)))
                .Get<TOptions>();
            return instance;
        }

        /// <summary>获取选项</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns>TOptions</returns>
        public static TOptions GetOptions<TOptions>(IServiceProvider serviceProvider = null) where TOptions : class, new()
        {
            IOptions<TOptions> service = GetService<IOptions<TOptions>>(serviceProvider ?? RootServices, false);
            return service?.Value;
        }

        /// <summary>获取选项</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns>TOptions</returns>
        public static TOptions GetOptionsMonitor<TOptions>(IServiceProvider serviceProvider = null)
            where TOptions : class, new()
        {
            IOptionsMonitor<TOptions> service =
                GetService<IOptionsMonitor<TOptions>>(serviceProvider ?? RootServices, false);
            return service?.CurrentValue;
        }

        /// <summary>获取选项</summary>
        /// <typeparam name="TOptions">强类型选项类</typeparam>
        /// <param name="serviceProvider"></param>
        /// <returns>TOptions</returns>
        public static TOptions GetOptionsSnapshot<TOptions>(IServiceProvider serviceProvider = null)
            where TOptions : class, new()
        {
            IOptionsSnapshot<TOptions> service = GetService<IOptionsSnapshot<TOptions>>(serviceProvider, false);
            return service?.Value;
        }

        #endregion
    }
}
